MyBatis 缓存之Redis简单实现 | 您所在的位置:网站首页 › mybatis redis缓存 › MyBatis 缓存之Redis简单实现 |
前言
MyBatis 提供的缓存机制都是基于Cache 接口而实现,因此我们也可以通过实现该接口创建自定义的缓存实现。 Redis 的缓存实现简单来说,在MyBatis开启二级缓存的前提下,通过使用自定义的缓存实现类,使用Redis完成对缓存信息的查询和更新。 先来看一下 maven 依赖,本文使用的是Spring boot框架,依赖信息相对简单清晰。 org.springframework.boot spring-boot-starter-data-redis org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.2再来看一下具体的实现类, public class RedisCache implements Cache { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final String id; private RedisTemplate redisTemplate; private static final long EXPIRE_TIME_IN_MINUTES = 30; public RedisCache(String id){ if(id == null) throw new IllegalArgumentException("Cache instance requires an ID"); this.id = id; } @Override public String getId() { return this.id; } private RedisTemplate getRedisTemplate() { if(null == this.redisTemplate){ logger.debug("set redisTemplate"); this.redisTemplate = ApplicationContextHolder.getBean("redisTemplate"); } return this.redisTemplate; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @Override public void putObject(Object key, Object value) { ValueOperations opsForValue = this.getRedisTemplate().opsForValue(); opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES); logger.debug("Put query result to redis"); } @Override public Object getObject(Object key) { ValueOperations opsForValue = this.getRedisTemplate().opsForValue(); logger.debug("Get cached query result from redis"); return opsForValue.get(key); } @Override public Object removeObject(Object key) { this.getRedisTemplate().delete(key); logger.debug("Remove cached query result from redis"); return key; } @Override public void clear() { this.getRedisTemplate().execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection redisConnection) throws DataAccessException { logger.debug("flush redis"); redisConnection.flushDb(); return null; } }); } @Override public int getSize() { return 0; } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } }这里我们采用了 RedisTemplate 实现对缓存的操作,而不是采用 jedis,原因在于Jedis是Redis官方推荐的面向Java的操作Redis的客户端,而RedisTemplate是SpringDataRedis中对JedisApi的高度封装。SpringDataRedis相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用。 需要注意的是,此处的 redisTemplate 属性不同通过 autowired 方式获得,原因在于 RedisCache 本身就不是一个bean,因此我们考虑使用一个辅助类实线bean的获取。 public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static ApplicationContext getApplicationContext(){ return context; } public static T getBean(Class clazz){ return context.getBean(clazz); } public static T getBean(String name){ return (T)context.getBean(name); } }最后还需要针对缓存做一些配置 mapper 文件内容相对简单,主要是基于主键信息的增删查改操作,此处不再赘述。 测试当我们使用浏览器发送下述请求时,能获得如下的相应信息, 而此时,Redis 数据库中存在如下的 key-value 信息, 当我们再次发送上述请求能够获得同样的响应信息,观察如下日志信息, 第一次请求的日志信息 第二次请求的日志信息 可以看出,每次查询的时候先查询缓存中是否存在相关信息,如果存在直接返回,如果不存在,则去访问数据库,并将结果信息写入缓存以供下次查询。 同样,我们可以借助 RESTClient 工具发送 post 请求,实现对数据库信息的修改, 而此时,Redis 数据库中的信息已被刷新, 这也说明了二级缓存的刷新时机,即事务的提交会刷新该namespace下的二级缓存。 总结本文描述了一种基于 RedisTemplate 的分布式缓存的简单实现方式,当然还有很多不足之处,比如缓存数据库崩溃等异常情况未考虑,希望能对读者在创建分布式缓存时提供一种思路。 |
CopyRight 2018-2019 实验室设备网 版权所有 |